import numpy as np
from functools import reduce

def _generate_dict_from_list( vec_list , prefix = "tmp" ):
    if len( vec_list ) == 0:
        raise Exception( "vector list must be non-zero length " )
    
    # generate temporary keys
    key_list = [ prefix + str(i) for i in xrange( len(vec_list) ) ]

    return key_list , dict( zip( key_list , vec_list ) )

def mean_direction_of_seq_no_keys( seq ):
    # the values are all contained in the seq
    key_list , key_value_pairs = _generate_dict_from_list( seq , "tmp" )
    return mean_direction_of_seq( key_list , key_value_pairs )

def is_the_same_id_no_keys( seq1 , seq2 ):
    key_list1 , key_value_pairs1 = _generate_dict_from_list( seq1 , "seq1_" )
    key_list2 , key_value_pairs2 = _generate_dict_from_list( seq2 , "seq2_" )

    merged_dict = dict( key_value_pairs1 , ** key_value_pairs2 )
    return is_the_same_id( key_list1 , key_list2 , merged_dict )

def mean_direction_of_seq( seq , key_value_pairs ):
    """
    seq contains a lot of keys which will be used to compute the mean
    direction of the whole union

    firstly convert the elements in the seq into unit ones

    secondly average the whole bunch of things

    at last do normalizatino again
    """
    if len( seq ) == 0:
        raise Exception( "seq must be non None" )

    # transfer the elements into numpy format
    key_value_pairs = dict( zip( key_value_pairs , \
            map( lambda x: np.array(x) , key_value_pairs.values() ) ) )

    # normalize all the elements
    def normalize( x ):
        length = np.sqrt( np.sum( np.square( x ) ) )
        return x / length

    key_value_pairs_norm = dict( zip( key_value_pairs , \
            map( normalize , key_value_pairs.values() ) ) )

    if len( seq ) == 1:
        return key_value_paris_norm[ seq[0] ]

    # map the string keys into numpy array so 
    # it could be used to do the reduce operation
    map_seq = list( map( lambda s: key_value_pairs_norm[s] , seq ) )
    ave_seq = reduce( lambda x, y: x+y , map_seq )

    return ave_seq / np.sqrt( np.sum( np.square( ave_seq ) ) )

def is_the_same_id( seq1 , seq2 , key_value_pairs ):
    """
    sequences contain a list of img names, each one performs as 
    a key in key_value_pairs, 

    key_value_pairs in a form,
    key = image_name, value = 2048 features from ReID

    ## first inport all the features in key_value_pairs, and then 
    normalize it into unit length, 

    compute the average angle of seq1 and seq2,
    compute the distance of angle( cosine distance ) and return
    """
    if len( seq1 ) == 0 or len( seq2 ) == 0:
        raise Exception( "seq1 or seq2 is empty list" )

    # transfer the values in the dict into numpy format
    key_value_pairs = dict( zip( key_value_pairs , \
            map( lambda x: np.array(x) , key_value_pairs.values() ) ) )

    # normalize all the elements
    def normalize( x ):
        length = np.sqrt( np.sum( np.square( x ) ) )
        return x / length

    key_value_pairs_norm = dict( zip( key_value_pairs , \
            map( normalize , key_value_pairs.values() ) ) )

    map_seq1 = list( map( lambda s: key_value_pairs_norm[s] , seq1 ) )
    map_seq2 = list( map( lambda s: key_value_pairs_norm[s] , seq2 ) )

    ave_seq1 = reduce( lambda x, y: x+y , map_seq1 )
    ave_seq2 = reduce( lambda x, y: x+y , map_seq2 )

    ave_seq1 = ave_seq1 / np.sqrt( np.sum( np.square(ave_seq1) ) )
    ave_seq2 = ave_seq2 / np.sqrt( np.sum( np.square(ave_seq2) ) )

    return 1. - np.sum( ave_seq1 * ave_seq2 )

if __name__ == "__main__":
    print( "no data!" )


